package parser.symbol;

import utils.CompileError;

import java.util.HashMap;
import java.util.Stack;

public class Table {
    public static int regCnt = 1;//寄存器计数 //函数reset到1
    public static StringBuilder llvm = new StringBuilder(); // 返回的llvm ir

    Stack<HashMap<String, Symbol>> symbolTable;
    HashMap<String, Symbol> globalTable;
    HashMap<String, Function> functionTable;

    int blockId;


    private static Table instance; // 单例模式

    private Table() {
        symbolTable = new Stack<>();

        globalTable = new HashMap<>();
        functionTable = new HashMap<>();
        blockId = -1; // 初始id为0.
        llvm.insert(0, "declare i32 @getint()\n" +
                "declare i32 @getarray(i32*)\n" +
                "declare i32 @getch()\n" +
                "declare void @putint(i32)\n" +
                "declare void @putch(i32)\n" +
                "declare void @putarray(i32,i32*)\n\n");
    }

    public static Table getInstance() {
        if (instance == null) {
            synchronized (Table.class) {
                if (instance == null) {
                    instance = new Table();
                }
            }
        }
        return instance;
    }

    public Symbol getSymbol(String name) throws CompileError {
        for (int i = blockId; i >= 0; i--) {
            if (symbolTable.get(i).get(name) != null) {
                return symbolTable.get(i).get(name);
            }
        }
        if (globalTable.get(name) != null) {
            return globalTable.get(name);
        }
        throw new CompileError(name + "未定义\nsymbolTable" + symbolTable + "\nglobalTable" + globalTable);
    }

    public void addSymbol(String name, Symbol symbol) throws CompileError {
        if (symbolTable.peek().get(name) != null) {
            throw new CompileError(name + "重定义\nsymbolTable" + symbolTable);
        }
        symbolTable.peek().put(name, symbol);
    }

    public void addFunction(String funcName, Function function) throws CompileError {
        if (functionTable.get(funcName) != null) {
            throw new CompileError(funcName + "函数重定义\nfuncTable" + functionTable);
        }
        functionTable.put(funcName, function);
    }


    public Function getFunction(String funcName) throws CompileError {
        if (functionTable.get(funcName) == null) {
            throw new CompileError(funcName + "函数未定义\nfuncTable" + functionTable);
        }
        return functionTable.get(funcName);
    }

    public void addBlock() {
        symbolTable.push(new HashMap<>());
        blockId++;
//        for (int i = 0; i <= blockId; i++) {
//            System.out.println(symbolTable.get(i));
//        }
    }

    public void leaveBlock() {
        symbolTable.pop();
        blockId--;
    }

    public int getBlockId() {
        return blockId;
    }


    public void addGlobal(String name, Symbol symbol) throws CompileError {
        if (globalTable.get(name) == null) {
            globalTable.put(name, symbol);
        } else {
            throw new CompileError("全局变量重定义" + name + "\nglobalTable" + globalTable);
        }
    }

    public Symbol getGlobal(String name) throws CompileError {
        if (globalTable.get(name) != null) {
            return globalTable.get(name);
        } else {
            throw new CompileError("全局变量中未定义" + name);
        }
    }

    public void printTable() {
        System.out.println("*********符号表*********");
        for (int i = blockId; i >= 0; i--) {
            System.out.println(symbolTable.get(i));
        }
        System.out.println("*********全局表*********");
        for (int i = 0; i < globalTable.size(); i++) {
            System.out.println(globalTable.get(i));
        }
//        System.out.println(globalTable);
        System.out.println("*********函数表*********");
        for (int i = 0; i < functionTable.size(); i++) {
            System.out.println(functionTable.get(i));
        }
//        System.out.println(functionTable);
    }
}
